#include "core.h"
#include "Compute.h"
#include <stdexcept>
#include <set>
#include <cstring>

using namespace std;

vector<string> getAllChains(const set<string>& words) {
    Compute compute(words);
    if (compute.hasCircle()) {
        throw logic_error("The words contain a circle.");
    }
    return compute.getAllChains();
}

WordChain getMaxWordChain(const set<string>& words, char h, char t, bool allowCircle) {
    Compute compute(words);
    if (!allowCircle && compute.hasCircle()) {
        throw logic_error("The words contain a circle.");
    }
    if (h != '\0' && t != '\0') {
        return compute.getLongestPathWithCirCleBetween(h, t, 0);
    } else if (h != '\0') {
        return compute.getLongestPathWithCirCleFrom(h, 0);
    } else if (t != '\0') {
        return compute.getLongestPathWithCirCleTo(t, 0);
    } else {
        return compute.getDiameterWithCircle(0);
    }
}

WordChain getMaxLetterChain(const set<string>& words, char h, char t, bool allowCircle) {
    Compute compute(words);
    if (!allowCircle && compute.hasCircle()) {
        throw logic_error("The words contain a circle.");
    }
    if (h != '\0' && t != '\0') {
        return compute.getLongestPathWithCirCleBetween(h, t, 1);
    } else if (h != '\0') {
        return compute.getLongestPathWithCirCleFrom(h, 1);
    } else if (t != '\0') {
        return compute.getLongestPathWithCirCleTo(t, 1);
    } else {
        return compute.getDiameterWithCircle(1);
    }
}

int gen_chains_all(char* words[], int len, char* result[]) {
    if (len == 0) {
        throw logic_error("Please ensure the words length is greater than zero.");
    }
    set<string> wordSet;
    for (int i = 0; i < len; i++) {
        wordSet.insert(string(words[i]));
    }
    vector<string> chains = getAllChains(wordSet);
    for (int i = 0; i < chains.size(); i++) {
        result[i] = new char[chains[i].length() + 1];
        strcpy(result[i], chains[i].c_str());
    }
    return (int) chains.size();
}

int gen_chain_word(char* words[], int len, char* result[], char head, char tail, char reject, bool enable_loop) {
    if (len == 0) {
        throw logic_error("Please ensure the words length is greater than zero.");
    }
    set<string> wordSet;
    for (int i = 0; i < len; i++) {
        if (words[i][0] == reject) {
            continue;
        }
        wordSet.insert(string(words[i]));
    }
    WordChain chain = getMaxWordChain(wordSet, head, tail, enable_loop);
    vector<Word> res = chain.getWords();
    for (int i = 0; i < res.size(); i++) {
        string chainString = res[i].toString();
        result[i] = new char[chainString.length() + 1];
        strcpy(result[i], chainString.c_str());
    }
    return chain.getWordNum();
}

int gen_chain_char(char* words[], int len, char* result[], char head, char tail, char reject, bool enable_loop) {
    if (len == 0) {
        throw logic_error("Please ensure the words length is greater than zero.");
    }
    set<string> wordSet;
    for (int i = 0; i < len; i++) {
        if (words[i][0] == reject) {
            continue;
        }
        wordSet.insert(string(words[i]));
    }
    WordChain chain = getMaxLetterChain(wordSet, head, tail, enable_loop);
    vector<Word> res = chain.getWords();
    for (int i = 0; i < res.size(); i++) {
        string chainString = res[i].toString();
        result[i] = new char[chainString.length() + 1];
        strcpy(result[i], chainString.c_str());
    }
    return chain.getWordNum();
}
